feat(app-server): add shared command - #2206
Conversation
f4102ea to
82aca78
Compare
limityan
left a comment
There was a problem hiding this comment.
结论:Request changes。
整体方向是合理的:Shared Host 留在 CLI app,Embedded/Shared 共用 AppServerTuiBackend,继续复用同一套 AgentRuntime 和 owner;Headless、ACP、SDK、Remote 也没有被强行收敛到 App Server。删除旧 v17 可以是最终形态。
但当前 PR 把“正式切换 --shared 并删除 v17”放在作用域、生命周期、恢复和回滚门槛之前。以下问题会直接影响现有 --shared,不适合留作合并后的后续债务。
1. 替换顺序与架构门槛倒置
问题: docs/architecture/app-server-architecture.md:60-73 要求先证明真实传输上限、workspace/execution 绑定、断连与并发语义、事件恢复、unknown outcome、生命周期和回滚条件;但迁移步骤在 :339-340 先切换正式 --shared、删除 v17,再“补齐 Shared 语义”。文档自身仍是 Proposed,PR 也没有记录 gate owner、验证证据或回滚/删除条件。
风险: 本 PR 删除了旧 v17 的 62 个故障合同测试,而新路径主要只有 4 个 transport/helper 单测和 1 个 in-memory subscription 测试。7/7 CI 通过只能说明现有检查为绿,不能证明 replacement parity。
建议: 先保留 v17,或让新路径继续以 opt-in 方式运行;完成并验证替换门槛后,再用独立、可回滚的 PR 切换 --shared 并删除旧实现。删除应是迁移的最后一步。
2. Shared Host 没有真正拥有 workspace / execution / capability scope
问题: src/apps/cli/src/shared_app_server.rs:186-221 只用 canonical workspace 创建 identity、lock 和 Runtime,随后暴露完整 BitfunAppServer 与 management surface(src/crates/interfaces/app-server/src/server.rs:225-267)。Host 没有注入不可变的 workspace/execution policy、local/remote policy 或 method allowlist。management handlers 仍直接信任请求中的 workspace_path;外部源更新还会向所有连接广播(server/event_forwarder.rs:157-165)。此外 Shared Host 暴露了 account/settings capability,却没有接管 Embedded 路径中的 session restore 与 settings sync 生命周期。
风险: 连接 workspace A 的客户端可以要求 A 的 Runtime/management owner 操作 workspace B,绕过 B 的 ownership domain;B 的更新也可能进入 A 的连接。客户端还会看到“可用”但 Host 实际没有运行完整生命周期的能力。
建议: 由 Shared Host 注入一个不可变的 Host policy/context,至少包含 canonical workspace、execution domain、remote policy、method/capability allowlist、真实 transport limits 和 capability lifecycle owner;所有 handler 在进入 owner 前 fail closed。
3. 断连后缺少 operation ownership,idle exit 会截断活跃 Turn
问题: connection EOF 在 src/apps/cli/src/shared_app_server.rs:331-343 直接结束任务;serve_connections 在 :249-284 只看 TCP connection 数量,最后一个连接消失 30 秒后退出,并不查询 active/queued Turn,也没有 cancel、detach 或 drain settlement。随后 Runtime 被 shutdown/drop。旧 v17 至少跟踪 active turn,并在释放连接前执行 cancel + terminal drain。
风险: 唯一 TUI 提交一个超过 30 秒的 Turn 后退出或崩溃,Host 会在 Turn 尚未 terminal/persisted 时销毁 owner。结果可能是 orphan operation、截断输出或副作用已发生但客户端无法判断结果。
建议: 增加 connection-owned operation registry 和精确 Turn identity,明确 cancel/detach/settle 策略;idle shutdown 必须同时满足“无客户端、无 active/queued operation”,并完成 Runtime-aware drain。取消 controller lease 可以是新控制模型,但不能同时删除 operation lifecycle contract。
4. 事件恢复和 transport outcome 合同尚未闭环
问题: runtime broadcast lag 时,App Server 会发送 Agent/Permission resync directive(server/event_forwarder.rs:95-132);TUI bridge 在 src/apps/cli/src/agent/tui_client.rs:1682-1712 只处理 Closed/Invalidated,Lagged 落入空分支,生产路径也没有触发 sync_events()。这会静默丢失 Agent 或 Permission 事件。
同时,Shared transport 的真实 request 上限是 128 KiB、response/event 是 8 MiB(shared_app_server.rs:27-30),initialize 却统一宣告 16 MiB(server/handlers/app.rs:45-55)。客户端 timeout 会标记 outcome_unknown=true,但连接/回调关闭被映射成普通 protocol error,再由 TUI 当作 outcome_unknown=false;对有副作用的请求,这无法区分“未提交”和“已提交但响应丢失”。
风险: 丢 Permission 事件可令 Turn 永久等待;错误的 frame 协商会让合法请求在底层断连;错误的 outcome classification 会诱导客户端安全性不足的重试。
建议: 在删除 v17 前完成 Lagged resync 或 fail-closed recovery;由 Host 返回真实且分方向的传输上限;对可能已提交的 mutation,将连接丢失视为 unknown outcome,并提供查询/settlement 恢复路径和真实 loopback 故障测试。
综上,我支持这个统一方向,但不支持当前替换顺序。请先补齐 Host policy、operation lifecycle、event/outcome recovery 以及对应的故障合同测试,证明 parity 与回滚条件后,再删除 v17。
Summary
Fixes #
Type and Areas
Type:
Areas:
Motivation / Impact
Verification
Reviewer Notes
Checklist